package com.gitee.wsl.common.chart.sample.radar

import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Path
import com.gitee.wsl.android.ext.math.calcArcEndPointXY
import com.gitee.wsl.common.chart.ChartEnum
import com.gitee.wsl.common.chart.adapter.DataSource
import com.gitee.wsl.common.chart.adapter.SelectItemChartAdapter
import com.gitee.wsl.common.chart.listener.click.PlotPointPosition
import com.gitee.wsl.android.ui.ext.type.drawLine
import com.gitee.wsl.common.chart.render.background.axis.line.CategoryLineAxis
import com.gitee.wsl.common.chart.render.background.axis.line.DataLineAxis
import com.gitee.wsl.common.chart.render.shape.plot.renderDot
import com.gitee.wsl.common.chart.sample.AbstractRadarChart
import com.gitee.wsl.common.chart.sample.radar.adapter.RadarChartAdapter
import com.gitee.wsl.common.chart.sample.radar.model.RadarData
import com.gitee.wsl.common.ui.draw.type.DotStyle
import com.gitee.wsl.android.ui.ext.type.drawRotateText
import com.gitee.wsl.android.ui.ext.type.textHeight
import com.gitee.wsl.math.Math
import com.gitee.wsl.jvm.math.add
import com.gitee.wsl.jvm.math.div
import com.gitee.wsl.jvm.math.sub

import timber.log.Timber


/**
 * @ClassName RadarChart
 * @Description  雷达图基类
 * @author XiongChuanLiang<br/>(xcl_168@aliyun.com)
 *
 */
class RadarChart(val adapter:RadarChartAdapter= RadarChartAdapter()):AbstractRadarChart(adapter),
    SelectItemChartAdapter<RadarData> by adapter{
    //数据源
    var dataSet by DataSource(adapter)

    //数据轴
    val dataAxis = DataLineAxis()

    //分类轴
    val categoryAxis = CategoryLineAxis()


    //依次存下每个圈上，每个标签节点的X,Y坐标
    var arrayDotX: Array<FloatArray> = emptyArray()
    var arrayDotY: Array<FloatArray> = emptyArray()

    var arrayLabelX: Array<FloatArray> = emptyArray()
    var arrayLabelY: Array<FloatArray> = emptyArray()


    //依次存下每个标签节点归属的圆心角度
    var arrayLabelAgent: FloatArray = FloatArray(0)

    //半径
    var arrayRadius: FloatArray = FloatArray(0)

    //外围标签偏移距离
    var labelOffset = 0f

    //透明度
    var areaAlpha = 100f
    val rdPath = Path()

    var radarChartType = ChartEnum.RadarChartType.RADAR

    init {
        dataAxis.tickMarksAlign=Paint.Align.LEFT
        dataAxis.tickMarkPaint.textAlign = Paint.Align.RIGHT
        dataAxis.hideTickMarks()
        plotLegend.isVisible=true
    }

    private fun clearArray() {
        arrayDotX = emptyArray()
        arrayDotY = emptyArray()
        arrayLabelX = emptyArray()
        arrayLabelY = emptyArray()
        
        //依次存下每个标签节点归属的圆心角度
        arrayLabelAgent = FloatArray(0)
        //半径
        arrayRadius = FloatArray(0)
    }

    override fun getType(): ChartEnum.ChartType {
        return ChartEnum.ChartType.RADAR
    }

    /**
     * 用来绘制蜘蛛网线
     */
    private fun drawGridLines(canvas: Canvas) {
        when (radarChartType) {
            ChartEnum.RadarChartType.RADAR -> drawGridLinesRadar(canvas)
            ChartEnum.RadarChartType.ROUND -> drawGridLinesRound(canvas)
        }
    }

    private fun drawGridLinesRadar(canvas: Canvas) {
        rdPath.reset()
        for (i in 0 until getAxisTickCount()) {
            for (j in 0 until getPlotAgentNumber()) {
                if (0 == j) {
                    rdPath.moveTo(arrayDotX[i][j], arrayDotY[i][j])
                } else {
                    rdPath.lineTo(arrayDotX[i][j], arrayDotY[i][j])
                }
            }
            rdPath.close()
            canvas.drawPath(rdPath, linePaint)
            rdPath.reset()
        }
    }

    private fun drawGridLinesRound(canvas: Canvas) {
        for (i in arrayRadius.indices) {
            canvas.drawCircle(
                bodyViewport.centerX,  bodyViewport.centerY,
                arrayRadius[i], linePaint
            )
        }
    }


    /**
     * 绘制各个圆心角的轴线
     * @param canvas 画布
     */
    private fun drawAxisLines(canvas: Canvas) {
        val cirX: Float = bodyViewport.centerX
        val cirY: Float =  bodyViewport.centerY

        //标签个数决定角的个数
        val labelsCount = getPlotAgentNumber()
        //轴线tick总数
        val dataAxisTickCount = getAxisTickCount()

        //轴线总数
        val i = dataAxisTickCount - 1
        for (j in 0 until labelsCount) {
            //用于绘制各个方向上的轴线
            canvas.drawLine(
                cirX, cirY, arrayDotX[i][j],
                arrayDotY[i][j], linePaint
            )
        } //end for labels													
    }


    /**
     * 绘制最外围的标签及主轴的刻度线标签
     * @param canvas 画布
     */
    private fun drawAxisLabels(canvas: Canvas) {
        //标签个数决定角的个数
        val labelsCount = getPlotAgentNumber()
        //轴线tick总数
        val dataAxisTickCount = getAxisTickCount()
        for (i in 0 until dataAxisTickCount) {
            for (j in 0 until labelsCount) {

                //绘制最外围的标签
                if (i == dataAxisTickCount - 1) {
                    //绘制最外围的标签		
                    val label: String = categoryAxis.dataSet.get(j)
                    canvas.drawText(
                        label,
                        arrayLabelX[i][j], arrayLabelY[i][j], labelPaint
                    )
                }


                //绘制主轴的刻度线与标签
                if (0 == j) { //显示在第一轴线上(即270度的那根线)										
                    //绘制主轴(DataAxis)的刻度线				
                    val tick: Float = dataAxis.axisSteps * i + dataAxis.axisMin
                    dataAxis.drawHorizontalTick(
                        left, bodyViewport.left, canvas,
                        arrayDotX[i][j],
                        arrayDotY[i][j],
                        tick.toString(),
                        arrayDotX[i][j],
                        arrayDotY[i][j],
                        true
                    )
                }
            } //end for labels		
        } //end for data
    }


    /**
     * 轴线上tick总个数
     * @return 总个数
     */
    private fun getAxisTickCount(): Int {
        return (dataAxis.axisTickCount + 1)
    }

    /**
     * 标签个数决定了图中角的个数
     * @return 标签总个数
     */
    private fun getPlotAgentNumber(): Int {
        return  categoryAxis.dataSet.size
    }

    /**
     * 设置外围标签位置的偏移距离
     * @param offset  偏移距离
     */
    fun setlabelOffset(offset: Int) {
        labelOffset = offset.toFloat()
    }

    /**
     * 得到所有相关的交叉点坐标
     */
    private fun calcAllPoints() {
        val cirX: Float = bodyViewport.centerX
        val cirY: Float =  bodyViewport.centerY

        //标签个数决定角的个数
        val labelsCount = getPlotAgentNumber()
        //轴线tick总数
        val dataAxisTickCount = getAxisTickCount()

        //扇形角度,依标签个数决定 				
        val pAngle = Math.div(360f, labelsCount.toFloat()) //   72f;

        //270为中轴线所处圆心角
        val initOffsetAgent = Math.sub(270f, pAngle)

        //依标签总个数算出环数,依数据刻度数决定
        val avgRadius = Math.div(radius, (dataAxisTickCount - 1).toFloat())

        //当前半径
        //float curRadius = 0.0f;
        //当前圆心角偏移量
        var offsetAgent = 0.0f

        //坐标与圆心角
        arrayDotX = Array(dataAxisTickCount) { FloatArray(labelsCount) }
        arrayDotY = Array(dataAxisTickCount) { FloatArray(labelsCount) }
        arrayLabelAgent = FloatArray(labelsCount)
        arrayLabelX = Array(dataAxisTickCount) { FloatArray(labelsCount) }
        arrayLabelY = Array(dataAxisTickCount) { FloatArray(labelsCount) }
        arrayRadius = FloatArray(dataAxisTickCount)
        val labelHeight = labelPaint.textHeight
        val labelRadius: Float = radius + labelHeight + labelOffset
        var currAgent = 0.0f
        for (i in 0 until dataAxisTickCount)  //数据轴
        {
            //curRadius = avgRadius * i; //当前半径长度，依此算出各节点坐标	
            arrayRadius[i] = avgRadius * i
            for (j in 0 until labelsCount) {
                offsetAgent = Math.add(initOffsetAgent, pAngle * j)
                currAgent = Math.add(offsetAgent, pAngle)

                //计算位置
                if (0f.compareTo(arrayRadius[i]) == 0) {
                    arrayDotX[i][j] = cirX
                    arrayDotY[i][j] = cirY
                } else {
                    val pointF= Math.calcArcEndPointXY(
                        cirX, cirY,
                        arrayRadius[i], currAgent
                    )
                    //点的位置
                    arrayDotX[i][j] = pointF.x
                    arrayDotY[i][j] = pointF.y
                }

                //记下每个标签对应的圆心角
                if (0 == i) arrayLabelAgent[j] = currAgent

                //外围标签位置
                val pointF= Math.calcArcEndPointXY(cirX, cirY, labelRadius, currAgent)
                arrayLabelX[i][j] = pointF.x
                arrayLabelY[i][j] = pointF.y
            } //end for labelCount					
        } //end for datacount		
    }


    /**
     * 绘制数据区网络
     * @param canvas 画布
     */
    private fun drawDataArea(canvas: Canvas) {
        val cirX: Float = bodyViewport.centerX
        val cirY: Float = bodyViewport.centerY
        var j = 0
        for (lineData in dataSet) {
            //画各自的网
            val dataset = lineData.linePointList
            val dataSize = dataset.size
            if (dataSize < 3) {
                Timber.d( "这几个数据可不够，最少三个起步.")
                continue
            }
            val arrayDataX = FloatArray(dataSize)
            val arrayDataY = FloatArray(dataSize)
            var i = 0
            for (data in dataset) {
                if (data.compareTo(0.0) == 0) {
                    arrayDataX[i] = bodyViewport.centerX
                    arrayDataY[i] =  bodyViewport.centerY
                    i++ //标签
                    continue
                }
                val per: Float = (data - dataAxis.axisMin) / dataAxis.axisRange
                val curRadius: Float = (radius * per).toFloat()

                //计算位置
                val pointF= Math.calcArcEndPointXY(
                    cirX, cirY, curRadius, arrayLabelAgent[i]
                )

                //依Path还是Line来决定画线风格
                arrayDataX[i] = pointF.x
                arrayDataY[i] = pointF.y
                i++ //标签
            }
            when (lineData.areaStyle) {
                ChartEnum.DataAreaStyle.FILL -> 
                    drawDataPath(canvas, lineData, arrayDataX, arrayDataY, j)
                ChartEnum.DataAreaStyle.STROKE ->
                    drawDataLine(canvas, lineData, arrayDataX, arrayDataY, j)
                else -> Timber.d( "这类型不认识.")
            }
            j++
        }
    }

    /**
     * 绘制数据连接线
     * @param canvas    画布
     * @param lineData    数据集类
     * @param arrayDataX    x坐标
     * @param arrayDataY    y坐标
     */
    private fun drawDataLine(
        canvas: Canvas,
        lineData: RadarData,
        arrayDataX: FloatArray, arrayDataY: FloatArray, dataID: Int
    ) {
        var startX = 0.0f
        var startY = 0.0f
        var initX = 0.0f
        var initY = 0.0f

        //PointF[] array = new PointF[arrayDataX.length];
        for (p in arrayDataX.indices) {
            if (0 == p) {
                startX = arrayDataX[p]
                initX = startX
                startY = arrayDataY[p]
                initY = startY
            } else {
                canvas.drawLine(lineData.lineSpacingStyle, startX, startY, arrayDataX[p], arrayDataY[p], lineData.plotLine.linePaint)
                startX = arrayDataX[p]
                startY = arrayDataY[p]
            }
        }
        //收尾
        canvas.drawLine(lineData.lineSpacingStyle, startX, startY, initX, initY,  lineData.plotLine.linePaint)

        //绘制点及对应的标签
        for (p in arrayDataX.indices) {
            drawDotAndLabel(canvas, lineData, arrayDataX[p], arrayDataY[p], dataID, p)
        }
    }


    /**
     * 绘制图网络线
     * @param canvas    画布
     * @param lineData    数据集类
     * @param arrayDataX    x坐标
     * @param arrayDataY    y坐标
     */
    private fun drawDataPath(
        canvas: Canvas,
        lineData: RadarData,
        arrayDataX: FloatArray, arrayDataY: FloatArray, dataID: Int
    ) {
        var initX = 0.0f
        var initY = 0.0f
        rdPath.reset()
        for (p in arrayDataX.indices) {
            if (0 == p) {
                initX = arrayDataX[p]
                initY = arrayDataY[p]
                rdPath.moveTo(initX, initY)
            } else {
                rdPath.lineTo(arrayDataX[p], arrayDataY[p])
            }
        }
        //收尾
        rdPath.lineTo(initX, initY)
        rdPath.close()
        val oldAlpha = lineData.plotLine.linePaint.alpha
        lineData.plotLine.linePaint.alpha = areaAlpha.toInt()
        canvas.drawPath(rdPath, lineData.plotLine.linePaint)

        //绘制点及对应的标签
        lineData.plotLine.linePaint.alpha = oldAlpha
        for (p in arrayDataX.indices) {
            drawDotAndLabel(canvas, lineData, arrayDataX[p], arrayDataY[p], dataID, p)
        }
        adapter.isRecordSetInited = true
    }

    private fun drawDotAndLabel(
        canvas: Canvas,
        lineData: RadarData,
        currentX: Float, currentY: Float,
        dataID: Int, childID: Int
    ) {
        val plotLine = lineData.plotLine
        val itemAngle = lineData.itemLabelRotateAngle
        if (plotLine.dotStyle != DotStyle.HIDE) {
            val pDot = plotLine.plotDot
            val radius = pDot.dotRadius
            canvas.renderDot(pDot, currentX, currentY, lineData.plotLine.dotPaint)
            savePointRecord(
                dataID, childID, currentX, currentY,
                currentX - radius, currentY - radius,
                currentX + radius, currentY + radius
            )
        }
        //是否显示标签
        if (lineData.isLabelVisible) {
            canvas.drawRotateText(
                this.getFormatterDotLabel(lineData.linePointList[childID]),
                currentX, currentY, itemAngle,
                 lineData.plotLine.dotLabelPaint
            )
        }
    }

    private fun getFormatterDotLabel(fl: Float): String {
       return fl.toString()
    }

    private fun savePointRecord(
        dataID: Int,
        childID: Int,
        currentX: Float,
        currentY: Float,
        fl: Float,
        fl1: Float,
        fl2: Float,
        fl3: Float
    ) {
       //selectHelper?.savePointRecord(dataID,childID,currentX,currentY,fl,fl1,fl2,fl3)
        if(adapter.isRecordSetInited) return
        val pRecord = PlotPointPosition()
        pRecord.savePlotDataID(dataID)
        pRecord.savePlotDataChildID(childID)
        pRecord.savePlotPosition(currentX, currentY)
        pRecord.savePlotRectF(left, top, right, bottom)
        adapter.addRecordItem(pRecord)
    }


    /**
     * 绘制图
     */
    protected fun drawPlot(canvas: Canvas) {
        calcAllPoints()
        drawGridLines(canvas)
        drawAxisLines(canvas)
        drawDataArea(canvas)
        drawAxisLabels(canvas)
        //图例
        //plotLegend.renderRdKey(canvas, mDataSet)
        clearArray()
    }

    override fun readerBackground(canvas: Canvas) {
        super.readerBackground(canvas)
        bodyViewport.render(canvas)
    }

    override fun renderBody(canvas: Canvas): Boolean {

            super.renderBody(canvas)

           /* //计算主图表区范围
            calcPlotRange()
            //画Plot Area背景			
            bodyViewport.render(canvas)
            //绘制标题
            drawTitle(canvas)*/

            //绘制图表
            drawPlot(canvas)

            /*//显示焦点
            drawFocusShape(canvas)

            //响应提示
            drawToolTip(canvas)*/
        return true
    }
    
}